// Package handlers provides HTTP handlers for internal endpoints
package handlers

import (
	"net/http"
	"runtime"
	"time"

	"gitee.com/zhenyangze/gin-framework/internal/pkg/container"
	"github.com/gin-gonic/gin"
)

// HealthHandler provides health check endpoints
type HealthHandler struct {
	container *container.Container
}

// NewHealthHandler creates a new health handler
func NewHealthHandler(container *container.Container) *HealthHandler {
	return &HealthHandler{
		container: container,
	}
}

// HealthCheck returns the health status of the application
func (h *HealthHandler) HealthCheck(c *gin.Context) {
	status := gin.H{
		"status":    "healthy",
		"timestamp": time.Now().UTC().Format(time.RFC3339),
		"version":   h.container.Config().GetString("app.version"),
		"services":  h.container.Health(),
		"system":    h.getSystemInfo(),
	}

	// Check if any service is unhealthy
	services := status["services"].(map[string]interface{})
	allHealthy := true
	for _, service := range services {
		if serviceStatus, ok := service.(map[string]interface{}); ok {
			if serviceStatus["status"] != "healthy" {
				allHealthy = false
				break
			}
		}
	}

	if !allHealthy {
		status["status"] = "unhealthy"
		c.JSON(http.StatusServiceUnavailable, status)
		return
	}

	c.JSON(http.StatusOK, status)
}

// ReadinessCheck returns whether the application is ready to serve requests
func (h *HealthHandler) ReadinessCheck(c *gin.Context) {
	// Check database connection
	db := h.container.DB()
	if db != nil {
		sqlDB, err := db.DB()
		if err != nil || sqlDB.Ping() != nil {
			c.JSON(http.StatusServiceUnavailable, gin.H{
				"status": "not_ready",
				"reason": "database_not_available",
			})
			return
		}
	}

	// Check Redis connection
	redis := h.container.Redis()
	if redis != nil {
		if err := redis.Ping().Err(); err != nil {
			c.JSON(http.StatusServiceUnavailable, gin.H{
				"status": "not_ready",
				"reason": "redis_not_available",
			})
			return
		}
	}

	c.JSON(http.StatusOK, gin.H{
		"status": "ready",
		"timestamp": time.Now().UTC().Format(time.RFC3339),
	})
}

// LivenessCheck returns whether the application is alive
func (h *HealthHandler) LivenessCheck(c *gin.Context) {
	c.JSON(http.StatusOK, gin.H{
		"status":    "alive",
		"timestamp": time.Now().UTC().Format(time.RFC3339),
		"uptime":    time.Since(startTime).String(),
	})
}

// MetricsHandler returns basic application metrics
func (h *HealthHandler) MetricsHandler(c *gin.Context) {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)

	metrics := gin.H{
		"timestamp": time.Now().UTC().Format(time.RFC3339),
		"memory": gin.H{
			"alloc_bytes":      m.Alloc,
			"total_alloc_bytes": m.TotalAlloc,
			"sys_bytes":        m.Sys,
			"num_gc":           m.NumGC,
		},
		"goroutines": runtime.NumGoroutine(),
		"cpu_count":  runtime.NumCPU(),
		"uptime":     time.Since(startTime).String(),
	}

	c.JSON(http.StatusOK, metrics)
}

// getSystemInfo returns basic system information
func (h *HealthHandler) getSystemInfo() gin.H {
	var m runtime.MemStats
	runtime.ReadMemStats(&m)

	return gin.H{
		"go_version":   runtime.Version(),
		"goroutines":   runtime.NumGoroutine(),
		"memory_mb":    bToMb(m.Alloc),
		"cpu_count":    runtime.NumCPU(),
		"uptime":       time.Since(startTime).String(),
	}
}

// bToMb converts bytes to megabytes
func bToMb(b uint64) uint64 {
	return b / 1024 / 1024
}

// startTime records when the application started
var startTime = time.Now()